package org.ytor.core.sqlflow;

import org.ytor.common.classmeta.ClassMetadata;
import org.ytor.common.classmeta.MethodMetadata;
import org.ytor.common.exception.BaseException;
import org.ytor.common.util.Colls;
import org.ytor.common.util.Strs;
import org.ytor.common.util.cache.C;
import org.ytor.common.util.cache.ClassCache;
import org.ytor.core.holder.U;
import org.ytor.core.model.LoginUser;
import org.ytor.core.sqlflow.anno.Table;
import org.ytor.core.sqlflow.builder.select.FromStage;
import org.ytor.core.sqlflow.builder.support.UpdateBuilder;
import org.ytor.core.sqlflow.builder.support.WhereBuilder;
import org.ytor.core.sqlflow.executor.DMLResult;
import org.ytor.core.util.Pages;

import java.lang.reflect.InvocationTargetException;
import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Consumer;

/**
 * created by yangtong on 2025/8/10 00:25:35
 * <br/>
 * SQL 基础操作层
 */
public abstract class BaseRepository<T extends PersistenceModel<T, ?>> {

    /**
     * 实体类型
     */
    private Class<T> modelType;

    /**
     * 实体类的字段
     */
    private Map<String, MethodMetadata> parseBeanToSet;

    @SuppressWarnings("unchecked")
    void initEntityClazz(Class<?> modelCls) {
        if (this.modelType == null) {
            this.modelType = (Class<T>) modelCls;

            // 解析当前class
            ClassMetadata<T> classMetadata = ClassCache.get(this.modelType);
            List<MethodMetadata> getters = classMetadata.getMethods(m ->
                    m.getName().startsWith("get") && m.parameters().isEmpty() && m.isPublic());

            parseBeanToSet = new LinkedHashMap<>();
            for (MethodMetadata getter : getters) {
                // 字段名称
                String fieldName = Strs.toUnderline(getter.getName().substring(3));
                if ("id".equals(fieldName)) {
                    continue;
                }
                parseBeanToSet.put(fieldName, getter);
            }

            // 建立实体类与表名称的映射
            Table tableAnno = classMetadata.getAnnotation(Table.class);
            String tableName;
            if (tableAnno == null || Strs.isEmpty(tableAnno.value())) {
                tableName = Strs.toUnderline(classMetadata.getSimpleNmae());
            } else {
                tableName = tableAnno.value();
            }
            C.put("TABLE-NAME-CLASS-CACHE::" + tableName, classMetadata.getSourceClass());
        }
    }

    public Class<T> modelType() {
        return this.modelType;
    }

    /**
     * 根据id查询数据
     */
    public final T queryById(String id) {
        return SQLHelper
                .select()
                .from(modelType)
                .where(w -> w.eq("id", id)).one();
    }

    /**
     * 根据id数组查询数据
     */
    public final List<T> queryById(Collection<?> ids) {
        return SQLHelper
                .select()
                .from(modelType)
                .where(w -> w.in("id", ids)).list();
    }

    /**
     * 根据条件查询唯一数据
     */
    public final T queryOne(Consumer<WhereBuilder> where) {
        return SQLHelper.select()
                .from(modelType)
                .where(where)
                .one();
    }

    /**
     * 根据条件查询所有数据
     */
    public final List<T> queryList(Consumer<WhereBuilder> where) {
        return SQLHelper.select()
                .from(modelType)
                .where(where)
                .list();
    }

    /**
     * 查询当前表全部数据
     */
    public final List<T> queryList() {
        return queryList(null);
    }

    /**
     * 指定分页，并根据条件查询对应的分页数据
     */
    public final Page<T> queryPage(Integer pageNo, Integer pageSize, Consumer<WhereBuilder> where) {
        return SQLHelper.select()
                .from(modelType)
                .where(where)
                .page(pageNo, pageSize);
    }

    /**
     * 根据条件查询分页数据
     */
    public final Page<T> queryPage(Consumer<WhereBuilder> where) {
        Page<?> page = Pages.getPage();
        return SQLHelper.select()
                .from(modelType)
                .where(where)
                .page(page.getPageNo(), page.getPageSize());
    }

    /**
     * 根据条件查询分页数据
     */
    public final Page<T> queryPage(Integer pageNo, Integer pageSize, WhereBuilder where) {
        return SQLHelper.select()
                .from(modelType)
                .where(where)
                .page(pageNo, pageSize);
    }

    /**
     * 根据条件查询分页数据
     */
    public final Page<T> queryPage(WhereBuilder where) {
        Page<?> page = Pages.getPage();
        return SQLHelper.select()
                .from(modelType)
                .where(where)
                .page(page.getPageNo(), page.getPageSize());
    }

    /**
     * 通用查询
     */
    @SafeVarargs
    public final FromStage select(SFunction<T, ?>... field) {
        return SQLHelper.select(field).from(modelType);
    }

    /**
     * 新增
     */
    public final DMLResult insert(T entity) {
        fieldFiller(entity, "insert");

        DMLResult dmlResult = SQLHelper.<T>insert().into(modelType).value(entity).submit();
        entity.setId(dmlResult.getId());
        return dmlResult;
    }

    /**
     * 批量新增
     */
    public final List<DMLResult> insertBatch(List<T> entities) {
        for (T entity : entities) {
            fieldFiller(entity, "insert");
        }

        List<DMLResult> dmlResults = SQLHelper.<T>insert().into(modelType).values(entities).submitBatch();
        for (int i = 0; i < dmlResults.size(); i++) {
            DMLResult dmlResult = dmlResults.get(i);
            entities.get(i).setId(dmlResult.getId());
        }
        return dmlResults;
    }

    /**
     * 编辑
     */
    public final DMLResult update(T entity) {
        if (entity.getId() == null) {
            throw new IllegalArgumentException("执行UPDATE时，id不能为空");
        }
        fieldFiller(entity, "update");

        UpdateBuilder<T> updateBuilder = SQLHelper.update(modelType);
        for (String fieldName : parseBeanToSet.keySet()) {
            MethodMetadata methodMetadata = parseBeanToSet.get(fieldName);
            try {
                updateBuilder.set(fieldName, methodMetadata.invoke(entity));
            } catch (InvocationTargetException | IllegalAccessException e) {
                throw new BaseException(e);
            }
        }

        updateBuilder.where(w -> w.eq("id", entity.getId()));
        return updateBuilder.submit();
    }

    /**
     * 通用查询
     */
    public final UpdateBuilder<T> update() {
        return SQLHelper.update(modelType);
    }

    /**
     * 批量新增或编辑数据
     */
    public final DMLResult insertOrUpdate(T entity) {
        if (entity.getId() == null) {
            return insert(entity);
        } else {
            return update(entity);
        }
    }

    /**
     * 根据id删除数据
     */
    public final DMLResult deleteById(Object... ids) {
        // 如果传的是 null 或空参数
        if (ids == null || ids.length == 0) {
            throw new IllegalArgumentException("id不能为空");
        }

        // 如果只有一个元素，再判断它是不是集合、数组还是普通对象
        if (ids.length == 1) {
            Object first = ids[0];

            if (first == null) {
                throw new IllegalArgumentException("id不能为空");
            }

            // 如果是 Collection
            if (first instanceof Collection<?> col) {
                return delete(w -> w.in("id", col));
            }
            // 如果是数组
            else if (first.getClass().isArray()) {
                return delete(w -> w.in("id", Colls.arrToList(first)));
            }
            // 否则当成单个 ID
            else {
                return delete(w -> w.eq("id", first));
            }
        }
        // 如果外部直接传了多个可变参数，就直接当 in 条件
        else {
            return delete(w -> w.in("id", Arrays.asList(ids)));
        }
    }

    /**
     * 根据条件删除数据
     */
    public final DMLResult delete(Consumer<WhereBuilder> where) {
        return SQLHelper.<T>delete().from(modelType).where(where).submit();
    }

    private void fieldFiller(T entity, String Type) {
        LoginUser loginUser = U.get();
        if (loginUser != null) {
            if (entity.getUpdateBy() == null) {
                entity.setUpdateBy(loginUser.getUserName());
            }
        }
        if (entity.getUpdateTime() == null) {
            entity.setUpdateTime(LocalDateTime.now());
        }

        if ("insert".equalsIgnoreCase(Type)) {
            if (loginUser != null) {
                if (entity.getDepartCode() == null) {
                    entity.setDepartCode(loginUser.getDepartCode());
                }
                if (entity.getCreateBy() == null) {
                    entity.setCreateBy(loginUser.getUserName());
                }
            }
            if (entity.getCreateTime() == null) {
                entity.setCreateTime(LocalDateTime.now());
            }
        }
    }
}
